package com.kexio.auth.service;

import java.util.List;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

/**
 * Redis键管理服务
 * 提供安全的批量删除和扫描功能
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Service
public class RedisKeyService {
    
    private static final Logger logger = LoggerFactory.getLogger(RedisKeyService.class);
    
    @Autowired(required = false)
    private StringRedisTemplate redisTemplate;
    
    /**
     * 使用SCAN命令安全地批量删除键
     * 避免使用KEYS命令造成Redis阻塞
     * 
     * @param pattern 匹配模式
     * @return 删除的键数量
     */
    public int scanAndDelete(String pattern) {
        if (redisTemplate == null) {
            logger.warn("Redis未配置，无法执行SCAN删除");
            return 0;
        }
        
        try {
            return redisTemplate.execute((RedisCallback<Integer>) connection -> {
                int totalDeleted = 0;
                Set<String> keysToDelete = new java.util.HashSet<>();
                
                try (Cursor<byte[]> cursor = connection.scan(
                        ScanOptions.scanOptions()
                            .match(pattern)
                            .count(500) // 每次扫描500个key，平衡性能和内存
                            .build())) {
                    
                    while (cursor.hasNext()) {
                        String key = new String(cursor.next());
                        keysToDelete.add(key);
                        
                        // 每1000个key批量删除一次，避免单次操作过大
                        if (keysToDelete.size() >= 1000) {
                            long deleted = connection.del(keysToDelete.stream()
                                .map(String::getBytes)
                                .toArray(byte[][]::new));
                            totalDeleted += deleted;
                            keysToDelete.clear();
                            
                            // 每删除1000个key后短暂休眠，减少对Redis的压力
                            try {
                                Thread.sleep(10);
                            } catch (InterruptedException e) {
                                Thread.currentThread().interrupt();
                                break;
                            }
                        }
                    }
                    
                    // 删除剩余的key
                    if (!keysToDelete.isEmpty()) {
                        long deleted = connection.del(keysToDelete.stream()
                            .map(String::getBytes)
                            .toArray(byte[][]::new));
                        totalDeleted += deleted;
                    }
                    
                } catch (Exception e) {
                    logger.error("SCAN操作过程中发生错误", e);
                }
                
                logger.info("SCAN删除完成: pattern={}, deleted={}", pattern, totalDeleted);
                return totalDeleted;
            });
            
        } catch (Exception e) {
            logger.error("SCAN删除失败: pattern={}", pattern, e);
            return 0;
        }
    }
    
    /**
     * 使用SCAN命令计算匹配键的数量
     * 
     * @param pattern 匹配模式
     * @return 匹配的键数量
     */
    public long scanCount(String pattern) {
        if (redisTemplate == null) {
            return 0;
        }
        
        try {
            return redisTemplate.execute((RedisCallback<Long>) connection -> {
                long count = 0;
                
                try (Cursor<byte[]> cursor = connection.scan(
                        ScanOptions.scanOptions()
                            .match(pattern)
                            .count(1000)
                            .build())) {
                    
                    while (cursor.hasNext()) {
                        cursor.next();
                        count++;
                    }
                    
                } catch (Exception e) {
                    logger.error("SCAN计数过程中发生错误", e);
                }
                
                return count;
            });
            
        } catch (Exception e) {
            logger.error("SCAN计数失败: pattern={}", pattern, e);
            return 0;
        }
    }
    
    /**
     * 使用SCAN命令获取匹配的所有键
     * 
     * @param pattern 匹配模式
     * @param limit 最大返回数量，0表示不限制
     * @return 匹配的键列表
     */
    public List<String> scanKeys(String pattern, int limit) {
        List<String> keys = new java.util.ArrayList<>();
        
        if (redisTemplate == null) {
            return keys;
        }
        
        try {
            redisTemplate.execute((RedisCallback<Void>) connection -> {
                try (Cursor<byte[]> cursor = connection.scan(
                        ScanOptions.scanOptions()
                            .match(pattern)
                            .count(1000)
                            .build())) {
                    
                    while (cursor.hasNext() && (limit == 0 || keys.size() < limit)) {
                        String key = new String(cursor.next());
                        keys.add(key);
                    }
                    
                } catch (Exception e) {
                    logger.error("SCAN获取键过程中发生错误", e);
                }
                
                return null;
            });
            
        } catch (Exception e) {
            logger.error("SCAN获取键失败: pattern={}", pattern, e);
        }
        
        return keys;
    }
    
    /**
     * 分批删除指定的键列表
     * 
     * @param keys 要删除的键列表
     * @return 实际删除的键数量
     */
    public int batchDelete(List<String> keys) {
        if (redisTemplate == null || keys == null || keys.isEmpty()) {
            return 0;
        }
        
        try {
            int totalDeleted = 0;
            int batchSize = 1000;
            
            for (int i = 0; i < keys.size(); i += batchSize) {
                int endIndex = Math.min(i + batchSize, keys.size());
                List<String> batch = keys.subList(i, endIndex);
                
                Long deleted = redisTemplate.delete(batch);
                totalDeleted += (deleted != null ? deleted.intValue() : 0);
                
                // 每批次之间短暂休眠
                if (endIndex < keys.size()) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
            
            logger.info("批量删除键完成: total={}, deleted={}", keys.size(), totalDeleted);
            return totalDeleted;
            
        } catch (Exception e) {
            logger.error("批量删除键失败", e);
            return 0;
        }
    }
}
